package com.example.socket;

import com.alibaba.fastjson.JSONObject;
import com.example.socket.util.*;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Classname ServletRequest
 * @Description TODO
 * @Date 2023/4/27 11:08
 * @Created by XiongXiong
 * @Author: X.I.O
 */
public class ServletRequest {

    private String url;

    private String path;

    private String queryParam;

    private String method;

    private Map<String,String> heards;

    private Map<String,Object> formData;

    private Map<String, List<String>> queryMap;

    private JSONObject json;

    private BufferedReader reader;

    private boolean isWebSocket;

    private InputStream inputStream;

    private String contentType;

    public ServletRequest(String url, String path,  String method, Map<String, String> heards, Map<String, Object> formData, Map<String, List<String>> queryMap, JSONObject json, InputStream inputStream, String contentType) {
        this.url = url;
        this.path = path;
        this.method = method;
        this.heards = heards;
        this.formData = formData;
        this.queryMap = queryMap;
        this.json = json;
        this.inputStream = inputStream;
        this.contentType = contentType;
    }

    public ServletRequest(InputStream inputStream) throws Exception {
        this.inputStream = inputStream;
        reader = new BufferedReader(new InputStreamReader(inputStream, ServletConstant.BYTE_CODE));
        String line;
        StringBuilder requestBody = new StringBuilder();
        int contentLength = 0;

        boolean isWebSocket=false;
        //-----------------------(预读)读取请求头部分---------------------------------
        while ((line = reader.readLine()) != null) {
            requestBody.append(line).append("\r\n");
            System.out.println(line);
            if (line.contains("Content-Length:")) {
                //---------------获取长度------------------------------------------
                contentLength = Integer.parseInt(line.substring("Content-Length:".length()).trim());
                break;
            }
            //-------------------判断是否是websocket----------------------------------
            if(line.contains("Upgrade: websocket")){
                isWebSocket = true;
            }
            //暂时没有报文了
            if(line.isEmpty()){
                break;
            }
        }
        if(isWebSocket){
            //----------------------是websocket-------------------------------------------
            Map<String,String> heards= HttpRequestParser.getHeaders(requestBody.toString());
            this.path=heards.get("Path");
            this.method=heards.get("Method");
            this.heards=heards;
            this.isWebSocket=true;
        }else {
            //----------------不是websocket------------------------------------

            //-----------------延时等待完整的报文(根据请求头数据长度)----------------------------------
            char[] buffer = new char[1024];
            StringBuilder requestBodyBuilder = new StringBuilder();
            int bytesRead;
            while (requestBodyBuilder.length() < contentLength && (bytesRead = reader.read(buffer)) != -1) {
                requestBodyBuilder.append(buffer, 0, bytesRead);
            }
            //------------------完整报文获取完毕-------------------------------------------------
            //完整报文
            String request = requestBody.toString() + "\r\n" + requestBodyBuilder.toString();

            //处理请求体
            Map<String,String> heards=HttpRequestParser.getHeaders(request);
            this.heards=heards;
            //处理请求类型
            String contentType=heards.get("Content-Type")==null ? "" : heards.get("Content-Type");
            this.contentType=contentType;
            if(contentType.contains("multipart/form-data")){
                //处理formdata数据
                String boundary=contentType.substring(contentType.indexOf("boundary=")+"boundary=".length());
                boundary="--"+boundary;
                Map<String,Object> formData= HttpFormDataParser.getFormDataStr(request,boundary);
                this.formData=formData;
            }else if(contentType.contains("application/json")){
                //处理 application/json
                String jsonStr= JsonExtractor.getJsonString(request);
                if(!"".equals(jsonStr)){
                    jsonStr= ServletStrUtils.getString(jsonStr);
                    JSONObject json=JSONObject.parseObject(jsonStr);
                    this.json=json;
                }
            }else if(contentType.contains("application/x-www-form-urlencoded")){
                //处理 x-www-form-urlencoded
                Map<String,List<String>> map= ServletQueryParamUtils.getQueryFormParams(request);
                if(!map.isEmpty()){
                    if(this.queryMap==null){
                        this.queryMap = new HashMap<String, List<String>>();
                    }
                    this.queryMap.putAll(map);
                }
            } else {
                System.out.println(contentType+" 请求类型");
                System.out.println(request);
            }


            String httpHead=request.split("\n")[0];
            url=request.split("\\s")[1];
            if(url.contains("?")){
                this.path=url.substring(0,url.indexOf("?"));
                this.queryParam=url.substring(url.indexOf("?")+1);
                //处理查询参数
                Map<String,List<String>> query= ServletQueryParamUtils.getQueryParamMap(this.queryParam);
                if(query.size() > 0){
                    if(this.queryMap==null){
                        this.queryMap=new HashMap<String, List<String>>();
                    }
                    this.queryMap.putAll(queryMap);
                }
            }else {
                this.path=url;
                this.queryParam="";
            }
            method=httpHead.split("\\s")[0];
        }

    }


    public void close() throws IOException {
        reader.close();
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getMethod() {
        return method;
    }

    public void setMethod(String method) {
        this.method = method;
    }

    public String getQueryParam() {
        return queryParam;
    }

    public void setQueryParam(String queryParam) {
        this.queryParam = queryParam;
    }

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }

    public Map<String, String> getHeards() {
        return heards;
    }

    public Map<String, Object> getFormData() {
        return formData;
    }

    public boolean isWebSocket() {
        return isWebSocket;
    }

    public InputStream getInputStream() {
        return inputStream;
    }

    private static Map<String, String> readHeaders(InputStream inputStream) throws IOException {
        Map<String, String> headers = new HashMap<>();
        while (true) {
            String line = readLine(inputStream);
            System.out.println(line);
            if (line.isEmpty()) {
                break;
            }
            int index = line.indexOf(":");
            if (index > 0) {
                headers.put(line.substring(0, index).trim(), line.substring(index + 1).trim());
            }
        }
        return headers;
    }

    private static String readLine(InputStream inputStream) throws IOException {
        StringBuilder sb = new StringBuilder();
        int c;
        while ((c = inputStream.read()) != -1) {
            if (c == '\r') {
                continue;
            } else if (c == '\n') {
                break;
            } else {
                sb.append((char) c);
            }
        }
        return sb.toString();
    }

    public JSONObject getJson() {
        return json;
    }

    public String getContentType() {
        return contentType;
    }

    public Map<String, List<String>> getQueryMap() {
        return queryMap;
    }

    public String getQueryParamsFirst(String name){
        if(this.queryMap==null){
            return null;
        }
        List<String> strings=this.queryMap.get(name);
        if(strings==null || strings.size()==0){
            return null;
        }
        return this.queryMap.get(name).get(0);
    }
}
